package com.joven.shelltest.utils;

import com.alibaba.fastjson.JSONObject;
import lombok.Getter;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * 获取证书信息工具
 * @Author wzj
 * @Date 2023-10-19 16:00
 **/
public class CertUtils {
    public static void main(String[] args) throws Exception {
        System.out.println(getCert("D:/image", "tseix_cert.crt"));
    }

    public static X509Certificate getCertInfo(String filePath, String fileName) {
        fileName = filePath + File.separator + fileName;
        try {
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            FileInputStream in = new FileInputStream(fileName);
            return (X509Certificate) cf.generateCertificate(in);
        } catch (CertificateException | FileNotFoundException e) {
            throw new RuntimeException(e);
        }
    }

    public static JSONObject getCert(String filePath, String fileName) {
        fileName = filePath + File.separator + fileName;
        JSONObject jsonObject = new JSONObject();
        X509Certificate cert;
        try {
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            FileInputStream in = new FileInputStream(fileName);
            cert = (X509Certificate) cf.generateCertificate(in);
        } catch (CertificateException | FileNotFoundException e) {
            throw new RuntimeException(e);
        }
        //签发者
        String subjectDn = cert.getSubjectDN().toString();
        //使用者
        String issuerDn = cert.getIssuerDN().toString();
        //序列号（十进制转十六进制，左补零）
        String serialNumber = String.format("%" + 20 + "s", cert.getSerialNumber().toString(16)).replace(' ', '0');
        //生效时间
        Date effDate = cert.getNotBefore();
        //过期时间
        Date expDate = cert.getNotAfter();
        DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String effStr = null;
        String expStr = null;
        try {
            effStr = sdf.format(effDate);
            expStr = sdf.format(expDate);
        } catch (Exception e) {
            e.printStackTrace();
        }
        //秘钥类型
        String type = cert.getPublicKey().getAlgorithm();
        //签名哈希算法
        String sigAlgName = cert.getSigAlgName();

        jsonObject.put("subjectDN", subjectDn);
        jsonObject.put("issuerDN", issuerDn);
        jsonObject.put("serialNumber", serialNumber);
        jsonObject.put("effDate", effStr);
        jsonObject.put("expDate", expStr);
        jsonObject.put("type", type);
        jsonObject.put("sigAlgName", CertType.getNameByCode(sigAlgName));
        jsonObject.put("publicKey", cert.getPublicKey());
        return jsonObject;
    }

    /**
     * 枚举类，实现数字证书对象标识Oid与名称的转换
     */
    @Getter
    public enum CertType {
        /**
         * RSA
         */
        rsaEncryption("1.2.840.113549.1.1.1", "RSA"),
        sha1withRSAEncryption("1.2.840.113549.1.1.5", "SHA1"),
        ECC("1.2.840.10045.2.1", "ECC"),
        SM2("1.2.156.10197.1.301", "SM2"),
        SM3WithSM2("1.2.156.10197.1.501", "SM3的SM2签名"),
        sha1withSM2("1.2.156.10197.1.502", "SHA1的SM2签名"),
        sha256withSM2("1.2.156.10197.1.503", "SHA256的SM2签名"),
        sm3withRSAEncryption("1.2.156.10197.1.504", "SM3的RSA签名"),
        commonName("2.5.4.3", "主体名"),
        emailAddress("1.2.840.113549.1.9.1", "邮箱"),
        cRLDistributionPoints("2.5.29.31", "CRL分发点"),
        extKeyUsage("2.5.29.37", "扩展密钥用法"),
        subjectAltName("2.5.29.17", "使用者备用名称"),
        CP("2.5.29.32", "证书策略"),
        clientAuth("1.3.6.1.5.5.7.3.2", "客户端认证");


        CertType(String code, String name) {
            this.code = code;
            this.name = name;
        }

        private String code;

        private String name;


        public void setCode(String code) {
            this.code = code;
        }

        public void setName(String name) {
            this.name = name;
        }

        public static String getNameByCode(String code) {
            CertType[] values = CertType.values();
            for (CertType plateColorEnum : values) {
                if (code.equals(plateColorEnum.getCode())) {
                    return plateColorEnum.getName();
                }
            }
            return null;
        }

        public static String getCodeByName(String name) {
            CertType[] values = CertType.values();
            for (CertType plateColorEnum : values) {
                if (name.equals(plateColorEnum.getName())) {
                    return String.valueOf(plateColorEnum.getCode());
                }
            }
            return null;
        }
    }
}
